module(..., package.seeall) -- 使得文件中的函数在何处都可调用
require "pins" -- 用到了pin库，该库为luatask专用库，需要进行引用
require "sys"
require "getLbsLoc"
require "rtos"
require "uartTask"
require "utils"
require "mqtt"
require "misc"
require "audio"
require "math"
require "nvm"
require "send433RFSignal"
require "logGenerator"
require "mqttOutMsg"
require "httpTask"
require "mqttInMsgQuakeInfoRel"
-- 初始化设备参数文件
nvm.init("config.lua", true)
-- 参数初始化 magnitude:震级
local warningColor, toneDowns, toneBreak, doToneTask, lampDowns, lampBreak,
      signalDowns, signalBreak, doSignalTask, sysTime, eqlog, errlog,
      alarm433Bool, ttsStr, slen, eventID, producerID, eventCancelID,
      producerCancelID, focal_longitude, focal_latitude, quake_intensity,
      quakeTimeStr, sendTime, magnitude, placeName, msgCode, actionMark,
      alertStr, isEarthquakeReport, areaCode, depth, msgID, msgSource,
      checkCode, versionAlarm, eEWID, serialNumber, recerver, warnningLevel,
      receiveTime, intensityLocalLast, emergencyLightOpenBreak,
      doEmergencyLightOpen = 0, 0, false, true, 0, false, 0, false, true, "",
                             "", "", false, "", string.len, "", "", "", "", 0.0,
                             0.0, 0.0, "", "", 0.0, "", "", false, "", false,
                             "510781006001", "", "", "", "", "", "", "", "", "",
                             "", 0, false, true
TTS = 1
DoLampTaskEarthquake = true
-- 地震预警系统
-- 两个功能：1.预警系统演练（tts语音播报3遍同时报警音触发）
-- 入参：jsondata接收的预警信息
local setGpio9Fnc = pins.setup(pio.P0_9, 1) -- 静音设置（高电平静音）
local setGpio10Fnc = pins.setup(pio.P0_10, 0) -- 预警指示
local setGpio11Fnc = pins.setup(pio.P0_11, 0) -- Buzzer正常低电平，预警高电平
local setGpio17Fnc = pins.setup(pio.P0_17, 0) -- 地震预警测试音量控制音量25%，高电平为测试音量（音量小），低电平为正常音量（音量大）
local setGpio16Fnc = pins.setup(pio.P0_16, 0) -- 地震预警测试音量控制音量50%，高电平为测试音量（音量小），低电平为正常音量（音量大）
local setGpio1Fnc = pins.setup(pio.P0_1, 0) -- 地震预警测试音量控制音量75%，高电平为测试音量（音量小），低电平为正常音量（音量大）
local setGpio2Fnc = pins.setup(pio.P0_2, 0) -- 红色
local setGpio3Fnc = pins.setup(pio.P0_3, 0) -- 蓝色
-- local setGpio12Fnc = pins.setup(pio.P0_12, 0) -- 报警灯
-- 获取配置参数
local clientNo, longitude, latitude, intensity, enable433, countDown,
      alertSound, alertLight, magnitudeConfig, centerIntensityConfig,
      emergencyLamp, relay, intensityReturn, regCenter, alertVolume, blueLimit,
      yellowLimit, orangeLimit, redLimit, afterSecond, blueGuide, yellowGuide,
      orangeGuide, redGuide, exerciseText, cancelCount, clientId, answerTopic,
      hz = nvm.get("info")[1], nvm.get("longitude"), nvm.get("latitude"),
           tonumber(nvm.get("intensity")), nvm.get("enable433"),
           tonumber(nvm.get("countDown")), tonumber(nvm.get("alertSound")),
           tonumber(nvm.get("alertLight")), tonumber(nvm.get("magnitude")),
           tonumber(nvm.get("centerIntensity")),
           tonumber(nvm.get("emergencyLamp")), tonumber(nvm.get("relay")),
           tonumber(nvm.get("intensityReturn")), nvm.get("regCenter"),
           tonumber(nvm.get("alertVolume")), tonumber(nvm.get("blueLimit")),
           tonumber(nvm.get("yellowLimit")), tonumber(nvm.get("orangeLimit")),
           tonumber(nvm.get("redLimit")), tonumber(nvm.get("afterSecond")),
           nvm.get("blueGuide"), nvm.get("yellowGuide"), nvm.get("orangeGuide"),
           nvm.get("redGuide"), nvm.get("exerciseText"),
           tonumber(nvm.get("cancelCount")), nvm.get("centerConfig")[6],
           nvm.get("centerConfig")[13], nvm.get("hz")
-- 报警灯一秒闪烁次数
local function lampSlash1s(hzSet)
    local flashTime = 0
    if hzSet == "01" then
        flashTime = 1
    elseif hzSet == "02" then
        flashTime = 2
    elseif hzSet == "03" then
        flashTime = 3
    elseif hzSet == "04" then
        flashTime = 4
    elseif hzSet == "05" then
        flashTime = 5
    elseif hzSet == "06" then
        flashTime = 6
    elseif hzSet == "07" then
        flashTime = 7
    elseif hzSet == "08" then
        flashTime = 8
    elseif hzSet == "09" then
        flashTime = 9
    elseif hzSet == "10" then
        flashTime = 10
    end
    return flashTime
end
-- 地震预警上报
local function eathquakeWarningReportHttp(distance, typeWarning, second,
                                          intensity)
    local url, sendMsg, body =
        "http://218.89.239.88:9889/externalService/receive/emergencyInformation",
        "", {}
    sendMsg = "{\n" .. "\"eventId\":" .. "\"" .. eventID .. "\"," ..
                  "\"quakeIntensity\":" .. "\"" .. quake_intensity .. "\"," ..
                  "\"distance\":" .. "\"" .. distance .. "\"," ..
                  "\"latitude\":" .. "\"" .. latitude .. "\"," .. "\"type\":" ..
                  "\"" .. typeWarning .. "\"," .. "\"quakeTime\":" .. "\"" ..
                  quakeTimeStr .. "\"," .. "\"sendTime\":" .. "\"" .. sendTime ..
                  "\"," .. "\"second\":" .. "\"" .. second .. "\"," ..
                  "\"intensity\":" .. "\"" .. intensity .. "\"," ..
                  "\"areaCode\":" .. "\"" .. areaCode .. "\"," .. "\"depth\":" ..
                  "\"" .. depth .. "\"," .. "\"location\":" .. "\"" .. placeName ..
                  "\"," .. "\"magnitude\":" .. "\"" .. magnitude .. "\"," ..
                  "\"longitude\":" .. "\"" .. longitude .. "\"}"
    body = {["dataJson"] = sendMsg}
    log.info("sendMsg", sendMsg)
    httpTask.earthquakeWarningReport(url, nil, body, 6000,
                                     "earthquakeWarningReport")
end

-- 预警事件ID组装
local function warningEventIdAssemble(quakeTimeStrGet)
    local datePre, timeSur, y, m, d, h, M, s = "", "", "", "", "", "", "", ""
    datePre = string.split(quakeTimeStrGet, " ")[1]
    timeSur = string.split(quakeTimeStrGet, " ")[2]
    y = string.split(datePre, "-")[1]
    m = string.split(datePre, "-")[2]
    d = string.split(datePre, "-")[3]
    h = string.split(timeSur, ":")[1]
    M = string.split(timeSur, ":")[2]
    s = string.split(timeSur, ":")[3]
    eventID = y .. m .. d .. h .. M .. s .. ".0001_1"
    return eventID
end

-- 获取系统时间
function GetSystemTime()
    local tClock, nowDate = os.date("*t"), ""
    local currentTime = os.time() + os.clock()
    local milliseconds = math.floor(currentTime * 1000) % 1000
    nowDate = string.format("%04d-%02d-%02d %02d:%02d:%02d", tClock.year,
                            tClock.month, tClock.day, tClock.hour, tClock.min,
                            tClock.sec)
    nowDate = nowDate .. "." .. milliseconds
    return nowDate
end

-- 烈度转换为阈值
local function intensity2Threshold(intensity2Th)
    local threhold = 0
    log.info("intensity2Th", intensity2Th, "blueLimit", blueLimit,
             "yellowLimit", yellowLimit, "redLimit", redLimit)
    if intensity2Th >= blueLimit and intensity2Th < yellowLimit then
        threhold = 1
    elseif intensity2Th >= yellowLimit and intensity2Th < orangeLimit then
        threhold = 2
    elseif intensity2Th >= orangeLimit and intensity2Th < redLimit then
        threhold = 3
    elseif intensity2Th >= redLimit then
        threhold = 4
    end
    return threhold
end
-- 应急照明灯打开任务
local function emergencyLightOpenTask()
    local emergencyLightOpenDowns = 0
    doEmergencyLightOpen = false
    setGpio11Fnc(1)
    while emergencyLightOpenDowns >= 0 and emergencyLightOpenDowns <= 5400 do
        if emergencyLightOpenBreak then
            emergencyLightOpenBreak = false
            break
        end
        sys.wait(1000)
        if emergencyLightOpenBreak then
            emergencyLightOpenBreak = false
            break
        end
        emergencyLightOpenDowns = emergencyLightOpenDowns + 1
    end
    setGpio11Fnc(0)
    doEmergencyLightOpen = true
end
-- 报警灯操作任务
local function alarmLampOperationTask(countDownSLamp, intensityGet)
    local countFlash = lampSlash1s(hz) -- 报警灯一秒闪烁次数
    local colorSelect = intensity2Threshold(intensityGet)
    log.info("colorSelect:", colorSelect, "countFlash:", countFlash)
    DoLampTaskEarthquake = false
    lampDowns = countDownSLamp
    while lampDowns >= 0 do
        log.info("lampBreak:", lampBreak, "lampDowns:", lampDowns)
        if lampBreak then
            lampDowns = 0
            lampBreak = false
            break
        end
        if lampDowns % 2 == 0 then
            for i = 1, countFlash, 1 do
                if lampBreak then break end
                if colorSelect == 1 then -- 蓝灯闪烁一秒
                    setGpio2Fnc(1)
                    sys.wait(1000 / (2 * countFlash))
                    setGpio2Fnc(0)
                    sys.wait(1000 / (2 * countFlash))
                elseif colorSelect == 2 then -- 黄灯闪烁一秒
                    setGpio3Fnc(1)
                    -- setGpio13Fnc(1)
                    pins.setup(pio.P0_13, 1)
                    sys.wait(1000 / (2 * countFlash))
                    setGpio2Fnc(0)
                    -- setGpio13Fnc(0)
                    pins.setup(pio.P0_13, 0)
                    sys.wait(1000 / (2 * countFlash))
                elseif colorSelect == 3 then -- 橙灯闪烁一秒
                    pins.close(pio.P0_13)
                    log.info("橙色:", colorSelect)
                    setGpio3Fnc(1)
                    pio.pin.pwm(13, 55, 600, -1)
                    sys.wait(1000 / (2 * countFlash))
                    setGpio3Fnc(0)
                    pio.pin.pwm(13, 0, 0, -1)
                    sys.wait(1000 / (2 * countFlash))
                elseif colorSelect == 4 then -- 红灯闪烁一秒
                    log.info("红灯闪烁:", colorSelect)
                    setGpio3Fnc(1)
                    sys.wait(1000 / (2 * countFlash))
                    setGpio3Fnc(0)
                    sys.wait(1000 / (2 * countFlash))
                end
            end
        elseif lampDowns % 2 == 1 then
            if lampBreak then
                lampDowns = 0
                lampBreak = false
                break
            end
            sys.wait(1000)
        end
        if lampBreak then
            lampDowns = 0
            lampBreak = false
            break
        end
        lampDowns = lampDowns - 1
    end
    intensityLocalLast = 0
    DoLampTaskEarthquake = true
end
-- 发送433信号
local function send433SignalTask(countSignalDownS, intensity2F433)
    local afterSecondCount = afterSecond
    doSignalTask = false
    setGpio9Fnc(0)
    signalDowns = countSignalDownS
    send433RFSignal.InterruptSendMsg = true
    send433RFSignal.sendMsgTask()
    if not send433RFSignal.TimeId then
        send433RFSignal.signalRF433SerialCommunication(signalDowns,
                                                       intensity2F433, "0",
                                                       alarm433Bool)
    end
    sys.wait(1000)
    signalDowns = signalDowns - 1
    while signalDowns > 0 do
        if signalDowns == 1 then alarm433Bool = true end
        if not send433RFSignal.TimeId then
            send433RFSignal.signalRF433SerialCommunication(signalDowns,
                                                           intensity2F433, "0",
                                                           alarm433Bool)
        end
        if signalBreak then
            signalBreak = false
            signalDowns = 0
            break
        end
        sys.wait(1000)
        if signalBreak then
            signalBreak = false
            signalDowns = 0
            break
        end
        signalDowns = signalDowns - 1
    end
    if afterSecondCount > 0 then
        sys.taskInit(alarmLampOperationTask, afterSecondCount, intensity2F433)
    end
    while afterSecondCount > 0 do
        if not send433RFSignal.TimeId then
            send433RFSignal.signalRF433SerialCommunication(0, intensity2F433,
                                                           "0", alarm433Bool)
        end
        if signalBreak then
            signalBreak = false
            signalDowns = 0
            break
        end
        sys.wait(1000)
        if signalBreak then
            signalBreak = false
            signalDowns = 0
            break
        end
        afterSecondCount = afterSecondCount - 1
    end
    setGpio9Fnc(1) -- 报警结束设置静音
    doSignalTask = true
    alarm433Bool = false
    intensityLocalLast = 0
    -- sys.wait(5000)
    if alertVolume <= 75 and alertVolume > 50 then
        setGpio1Fnc(0)
        log.info("音量为75，结束")
    elseif alertVolume <= 50 and alertVolume > 20 then
        setGpio16Fnc(0)
        log.info("音量为50，结束")
    elseif alertVolume <= 25 and alertVolume > 0 then
        setGpio17Fnc(0)
        log.info("音量为25，结束")
    end -- 音量测试恢复正常（大音量）
end

-- 预警声音播报任务
local function alarmVoiceTask(countDownS)
    setGpio9Fnc(0)
    -- local count = 0
    doToneTask = false
    toneDowns = countDownS
    audio.play(TTS, "TTS", alertStr, 7)
    while toneDowns > 0 do
        log.info("toneDowns", toneDowns)
        if toneDowns <= 10 then
            ttsStr = tostring(toneDowns)
            audio.play(TTS, "TTS", ttsStr, 7)
        end
        if toneBreak then
            toneBreak = false
            toneDowns = 0
            -- uartTask.write(0x0C)
            break
        end
        -- if math.fmod(count, 12) == 0 then uartTask.write(0x0C) end
        sys.wait(1000)
        if toneBreak then
            toneBreak = false
            toneDowns = 0
            -- uartTask.write(0x0C)
            break
        end
        toneDowns = toneDowns - 1
        -- count = count + 1
    end
    intensityLocalLast = 0
    setGpio9Fnc(1)
    doToneTask = true
end

-- 演习或演练声音播报
local function alarmDrillVoiceTask(countDownS)
    doToneTask = false
    setGpio9Fnc(0)
    setGpio10Fnc(1)
    toneDowns = countDownS
    audio.play(TTS, "TTS", ttsStr, 7)
    while toneDowns > 0 do
        if toneDowns <= 10 then
            log.info("tts voice")
            ttsStr = tostring(toneDowns)
            audio.play(TTS, "TTS", ttsStr, 7)
        end
        -- if math.fmod(countAlarmDrill, 12) == 0 then uartTask.write(0x0C) end
        if toneBreak then
            -- uartTask.write(0x0C)
            toneBreak = false
            toneDowns = 0
            break
        end
        sys.wait(1000)
        if toneBreak then
            -- uartTask.write(0x0C)
            toneBreak = false
            toneDowns = 0
            break
        end
        toneDowns = toneDowns - 1
        -- countAlarmDrill = countAlarmDrill + 1
    end
    setGpio9Fnc(1) -- 报警结束设置静音
    if alertVolume <= 75 and alertVolume > 50 then
        setGpio1Fnc(0)
        log.info("音量为75，结束，alarm")
    elseif alertVolume <= 50 and alertVolume > 20 then
        setGpio16Fnc(0)
        log.info("音量为50，结束，alarm")
    elseif alertVolume <= 25 and alertVolume > 0 then
        setGpio17Fnc(0)
        log.info("音量为25，结束，alarm")
    end -- 音量测试恢复正常（大音量）
    setGpio10Fnc(0)
    doToneTask = true
    intensityLocalLast = 0
end

-- string转time
local function string2time(str)
    log.info("str", str)
    local dateStr, timeStr = "", ""
    dateStr = string.split(str, " ")[1]
    timeStr = string.split(str, " ")[2]
    local Y = string.split(dateStr, "-")[1]
    local m = string.split(dateStr, "-")[2]
    local d = string.split(dateStr, "-")[3]
    local H = string.split(timeStr, ":")[1]
    local M = string.split(timeStr, ":")[2]
    local S = string.split(timeStr, ":")[3]
    log.info("Y:", Y, "m:", m, "d:", d, "H:", H, "M:", M, "S:", S)
    return os.time({day = d, month = m, year = Y, hour = H, min = M, sec = S})
end

-- 烈度回传事件
local function intensityReturnTask(intensity, tjsondata, earthquakeTopic,
                                   countDownS, quakeTimeStr, focal_longitude,
                                   distance, placeName, focal_latitude)
    sysTime = GetSystemTime()
    local topic = "answer"
    local sendMsg = "{" .. "\"msgLogId\":" .. tostring(intensity) ..
                        ",\"clientNo\":" .. tostring(warningColor) ..
                        ",\"info\":\"{\"1\":\"" .. tostring(tjsondata["3"]) ..
                        "\",\"2\":\"" .. tostring(tjsondata["2"]) ..
                        "\",\"3\":\"" .. sysTime .. ",\"4\":" ..
                        tostring(tjsondata["3"]) .. ",\"5\":" ..
                        string.split(earthquakeTopic, "/")[2] ..
                        "\",\"6\":\"2d89cc\",\"7\":\"1\",\"8\":\"1\",\"9\":\"" ..
                        clientNo .. "\",\"10\":\"" .. tostring(tjsondata["16"]) ..
                        "\",\"11\":\"1\"}\",\"result\":\"{'1':" .. countDownS ..
                        ",'2':" .. intensity .. ",'3':" .. warningColor ..
                        ",'4':" .. quakeTimeStr .. ",'5':" .. placeName ..
                        ",'6':" .. tostring(magnitude) .. ",'7':" .. distance ..
                        ",'8':" .. focal_longitude .. ",'9':" .. focal_latitude ..
                        ",'10':" .. longitude .. ",'11':" .. latitude ..
                        "}\",\"answerTime\":" .. os.time() * 1000 .. "}"
    if sendMsg ~= "" then
        local sendKesonlog = ""
        sysTime = GetSystemTime()
        sendKesonlog = "[" .. sysTime .. "]" .. "[回传KESON系统信息:]" ..
                           sendMsg .. "\n"
        logGenerator.generateLogTask(sendKesonlog, "log")
    end
    sendMsg = crypto.aes_encrypt("ECB", "PKCS5", sendMsg, "keson-123abcdefg")
    sendMsg = crypto.base64_encode(sendMsg, slen(sendMsg))
    mqttOutMsg.insertMsg(topic, sendMsg, 0)
end

local function round(x)
    return x >= 0 and math.floor(x + 0.5) or math.ceil(x - 0.5)
end

local function Algorithm(equipment_longitude, equipment_latitude,
                         focal_longitude1, focal_latitude1)
    local r = 6371
    local dlon = math.rad(equipment_longitude - focal_longitude1)
    local dlat = math.rad(equipment_latitude - focal_latitude1)
    local a = math.pow(math.sin(dlat / 2), 2) +
                  math.cos(math.rad(equipment_latitude)) *
                  math.cos(math.rad(focal_latitude)) *
                  math.pow(math.sin(dlon / 2), 2)
    local c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a))
    log.info("c:", c, "a:", a, "dlon:", dlon, "dlat:", dlat)
    local d = r * c
    local e = math.sqrt(d * d + tonumber(depth) * tonumber(depth))
    log.info("e:", e, "depth:", depth, "d:", d)
    return e
end

-- 预警参数组装
local function alert_parameter_assembly(tjsondata)
    if regCenter then -- 启用注册中心
        if tjsondata["2"] then -- 消息类型赋值
            msgCode = tjsondata["2"]
        end
        log.info("msgCode", msgCode)
        if "0199" == msgCode then -- 预警取消
            eventCancelID = tjsondata["7"]
            producerCancelID = tjsondata["8"]
        elseif "0101" == msgCode or "0201" == msgCode or "0301" == msgCode then -- 普通预警，普通预警演练，普通预警测试
            if tjsondata["1"] then msgID = tjsondata["1"] end -- 预警发布消息ID
            if tjsondata["2"] then msgCode = tjsondata["2"] end -- 消息类型 参考值：0101，0201，0301 0101，0201，0301
            if tjsondata["3"] then sendTime = tjsondata["3"] end -- 消息发送时间 地震发生时间，格式：YYYY-MM-DD hh:mm:ss.SSS （24小时，年-月-日 时:分：秒.毫秒）
            if tjsondata["4"] then msgSource = tjsondata["4"] end -- 来源 发布单元ID
            if tjsondata["5"] then checkCode = tjsondata["5"] end -- 校验码 用于消息体完整性、正确性校验,*后期如需要可加载数字签名
            if tjsondata["6"] then versionAlarm = tjsondata["6"] end -- 版本号 预警发布协议版本号
            if tjsondata["7"] then eEWID = tjsondata["7"] end -- 事件标识 地震事件Id
            if tjsondata["8"] then serialNumber = tjsondata["3"] end -- 序列号 地震预警事件的发布报文序号，其中：1为首报报文 255为终报
            if tjsondata["9"] then producerID = tjsondata["9"] end -- 生产者 生产单元Id，AAAAnn
            if tjsondata["10"] then recerver = tjsondata["10"] end -- 接收者 当消息类型为0201或0301时，为接收终端信息。当消息类型为其他时，此项为空。格式：“GRO:GGGnn”： GGGnn为分组groupId，分组策略由发布单元或注册中心管理；“UID:AAAAnn”:AAAAnn为接收终端ID
            if tjsondata["11"] then warnningLevel = tjsondata["11"] end -- 震中预警等级 包括：red（红色预警）、orange（橙色预警）、yellow（黄色预警）、blue（蓝色预警）
            if tjsondata["12"] then quakeTimeStr = tjsondata["12"] end -- 发震时间 地震发生时间，格式：YYYY-MM-DD hh:mm:ss.SSS （24小时，年-月-日 时:分：秒.毫秒）
            if tjsondata["13"] then placeName = tjsondata["13"] end -- 震中参考地名 Xx省xx市xx县，县级地名
            if tjsondata["14"] and tjsondata["15"] then
                focal_longitude = tonumber(tjsondata["14"]) -- 震中经度 震中经度，精度：小数点后三位，单位：度
                focal_latitude = tonumber(tjsondata["15"]) -- 震中纬度 震中纬度，精度：小数点后三位，单位：度
            end
            if tjsondata["16"] then depth = tjsondata["16"] end -- 深度 整数，单位：km
            if tjsondata["17"] then
                magnitude = tonumber(tjsondata["17"]) -- 震级 精度：一位小数
            end
            if tjsondata["18"] then
                quake_intensity = tonumber(tjsondata["18"]) -- 震中烈度 1-12之间数值，单位：度。显示时四舍五入显示。
            end
        elseif "0102" == msgCode or "0202" == msgCode or "0302" == msgCode then -- 专业预警，专业预警演练，专业预警测试
            if tjsondata["1"] then msgID = tjsondata["1"] end -- 预警发布消息ID
            if tjsondata["2"] then msgCode = tjsondata["2"] end -- 消息类型 参考值：0101，0201，0301 0101，0201，0301
            if tjsondata["3"] then sendTime = tjsondata["3"] end -- 消息发送时间 地震发生时间，格式：YYYY-MM-DD hh:mm:ss.SSS （24小时，年-月-日 时:分：秒.毫秒）
            if tjsondata["4"] then msgSource = tjsondata["4"] end -- 来源 发布单元ID
            if tjsondata["5"] then checkCode = tjsondata["5"] end -- 校验码 用于消息体完整性、正确性校验,*后期如需要可加载数字签名
            if tjsondata["6"] then versionAlarm = tjsondata["6"] end -- 版本号 预警发布协议版本号
            if tjsondata["7"] then eEWID = tjsondata["7"] end -- 事件标识 地震事件Id
            if tjsondata["12"] then sendTime = tjsondata["12"] end
            if tjsondata["16"] then placeName = tjsondata["16"] end
            if tjsondata["17"] and tjsondata["18"] then
                focal_longitude = tonumber(tjsondata["17"])
                focal_latitude = tonumber(tjsondata["18"])
            end
            if tjsondata["21"] then
                quake_intensity = tonumber(tjsondata["21"])
            end
            if tjsondata["15"] then quakeTimeStr = tjsondata["15"] end
            if tjsondata["19"] then depth = tjsondata["19"] end
            if tjsondata["20"] then
                magnitude = tonumber(tjsondata["20"])
            end
        end
    else -- keson地震预警监控平台
        if tjsondata["7"] then focal_longitude = tonumber(tjsondata["7"]) end
        if tjsondata["8"] then focal_latitude = tonumber(tjsondata["8"]) end
        if tjsondata["11"] then
            quake_intensity = tonumber(tjsondata["11"])
        end
        if tjsondata["5"] then
            quakeTimeStr = tjsondata["5"]
            eventID = warningEventIdAssemble(quakeTimeStr)
        end
        if tjsondata["10"] then magnitude = tonumber(tjsondata["10"]) end
        if tjsondata["13"] then placeName = tjsondata["13"] end
        if tjsondata["16"] then msgCode = tjsondata["16"] end
        sendTime = GetSystemTime()
        depth = "10"
    end
end
-- 小数取整：4舍五入
local function decimalToInit(decimalGet)
    local initRetur, decimalRetur
    if decimalGet >= 0 then
        initRetur, decimalRetur = math.modf(decimalGet)
        if decimalRetur >= 0.5 then initRetur = initRetur + 1 end
    else
        initRetur = 0
    end

    return initRetur
end
-- 预警取消
local function cancel_alert_event()
    local strAlertCancel = ""
    if not doToneTask then toneBreak = true end
    if not DoLampTaskEarthquake then lampBreak = true end
    if not doSignalTask then signalBreak = true end
    while not doSignalTask do sys.wait(300) end
    if not doEmergencyLightOpen then emergencyLightOpenBreak = true end
    while not doEmergencyLightOpen do sys.wait(300) end
    if not send433RFSignal.TimeId then
        send433RFSignal.InterruptSendMsg = false
        send433RFSignal.sendMsgTask()
    end
    audio.stop()
    setGpio9Fnc(0)
    log.info("cancelCount:", cancelCount)
    if cancelCount > 0 then
        for i = 1, cancelCount do
            strAlertCancel = strAlertCancel .. "地震预警取消。"
        end
        audio.play(TTS, "TTS", strAlertCancel, 7)
        sys.wait(2200 * cancelCount)
    end
    setGpio9Fnc(1) -- 报警结束设置静音
end
-- 地震预警上报-注册中心
local function eathquakeWarningReportRegCenter(intensityLocalGet, distanceGet,
                                               countDownSGet)
    local sendMsg, timeSendToIot, leds, sounds, display, threshold = "", "", "",
                                                                     "", "", 0
    timeSendToIot = GetSystemTime()
    display = "no"
    threshold = intensity2Threshold(intensityLocalGet)
    if "0199" == msgCode then
        if toneBreak == false and signalBreak == false then
            sounds = "yes"
        else
            sounds = "no"
        end
        if lampBreak == false then
            leds = "yes"
        else
            leds = "no"
        end
    else
        if threshold < countDown and threshold < alertSound then
            sounds = "no"
        elseif threshold >= countDown or threshold >= alertSound then
            sounds = "yes"
        end
        if intensityLocalGet >= alertLight then
            leds = "yes"
        else
            leds = "no"
        end
    end

    if "0199" == msgCode then
        sendMsg = "{" .. "\"1\":\"" .. msgID .. "\",\"2\":\"" .. msgCode ..
                      "\",\"3\":\"" .. receiveTime .. "\",\"4\":\"" ..
                      timeSendToIot .. "\",\"5\":\"" .. clientId ..
                      "\",\"6\":\"" .. checkCode .. "\",\"7\":\"" ..
                      versionAlarm .. "\",\"8\":\"" .. eEWID .. "\",\"9\":\"" ..
                      msgSource .. "\",\"10\":{" .. "\"Leds\":" .. "\"" .. leds ..
                      "\",\"Sounds\":\"" .. sounds .. "\",\"Display\":\"" ..
                      display .. "\"}}"
    elseif "0101" == msgCode or "0201" == msgCode or "0301" == msgCode then
        sendMsg = "{\"1\":\"" .. msgID .. "\",\"2\":\"" .. msgCode ..
                      "\",\"3\":\"" .. receiveTime .. "\",\"4\":\"" ..
                      timeSendToIot .. "\",\"5\":\"" .. clientId ..
                      "\",\"6\":\"" .. checkCode .. "\",\"7\":\"" ..
                      versionAlarm .. "\",\"8\":\"" .. eEWID .. "\",\"9\":\"" ..
                      msgSource .. "\",\"10\":\"" .. warnningLevel ..
                      "\",\"11\":{" .. "\"Leds\":" .. "\"" .. leds ..
                      "\",\"Sounds\":\"" .. sounds .. "\",\"Display\":\"" ..
                      display .. "\"}}"
    elseif "0102" == msgCode or "0202" == msgCode or "0302" == msgCode then
        sendMsg = "{" .. "\"1\":\"" .. msgID .. "\",\"2\":\"" .. msgCode ..
                      "\",\"3\":\"" .. receiveTime .. "\",\"4\":\"" ..
                      timeSendToIot .. "\",\"5\":\"" .. clientId ..
                      "\",\"6\":\"" .. checkCode .. "\",\"7\":\"" ..
                      versionAlarm .. "\",\"8\":\"" .. eEWID .. "\",\"9\":" ..
                      "\"" .. msgSource .. "\",\"10\":" .. "\"" .. warnningLevel ..
                      "\"," .. "\"11\":{" .. "\"Leds\":" .. "\"" .. leds ..
                      "\",\"Sounds\":\"" .. sounds .. "\",\"Display\":\"" ..
                      display .. "\"},\"12\":\"" .. intensityLocalGet ..
                      "\",\"13\":\"" .. distanceGet .. "\",\"14\":\"" ..
                      countDownSGet .. "\"}"
    end
    if sendMsg ~= "" then
        local sendBlog = ""
        sendBlog = "[" .. timeSendToIot .. "]" .. "[回传B系统信息:]" ..
                       sendMsg .. "\n"
        logGenerator.generateLogTask(sendBlog, "log")
        mqttOutMsgQuakeRel.insertQuakeRelMsg(answerTopic, sendMsg, 0)
    end
end

-- 地震预警动作执行
local function earthquake_alert_action(aesDecryptMsg, tjsondata, earthquakeTopic)
    sysTime = GetSystemTime()
    eqlog = eqlog .. "[" .. sysTime .. "]" ..
                "接收到的地震预警消息内容:" .. aesDecryptMsg .. "\n"
    if "false" == enable433 then enable433 = false end
    if "true" == enable433 then enable433 = true end
    actionMark = true
    local sysTimeOs = os.time()
    local quakeTime = string2time(quakeTimeStr)
    -- 计算距离
    local distance = decimalToInit(Algorithm(longitude, latitude,
                                             focal_longitude, focal_latitude))
    log.info("distance", distance)
    -- 计算S波到达时间 减1秒网络延时
    log.info("distance / 3.55:", (distance / 3.55), "sysTimeOs:", sysTimeOs,
             "quakeTime:", quakeTime, "sysTimeOs - quakeTime",
             (sysTimeOs - quakeTime))
    local countDownS =
        decimalToInit((distance / 3.55) - (sysTimeOs - quakeTime))
    log.info("countDownS:", countDownS)
    -- 烈度计算
    local intensityLocal = decimalToInit(round(
                                             quake_intensity - 4 *
                                                 math.log10(distance / 10 + 1.0)))
    log.info("intensity", intensityLocal)
    if intensityLocal <= 0 then intensityLocal = 1 end
    if isEarthquakeReport then
        eathquakeWarningReportHttp(distance, "EEW", countDownS, intensityLocal)
    end
    warningColor = intensity2Threshold(intensityLocal)
    if warningColor == 1 then
        alertStr = blueGuide .. blueGuide .. blueGuide
    elseif warningColor == 2 then
        alertStr = yellowGuide .. yellowGuide .. yellowGuide
    elseif warningColor == 3 then
        alertStr = orangeGuide .. orangeGuide .. orangeGuide
    elseif warningColor == 4 then
        alertStr = redGuide .. redGuide .. redGuide
    end
    sysTime = GetSystemTime()
    eqlog = eqlog .. "[" .. sysTime .. "]" .. "[地震预警信息:]" ..
                "震源距离:" .. tostring(distance) .. "KM,s波到达时间:" ..
                tostring(countDownS) .. "s,烈度:" .. tostring(intensityLocal) ..
                "\n"
    -- 地震烈度大于等于设定预警临界值则执行报警
    log.info("intensityLocal:", intensityLocal, "intensity:", intensity,
             "magnitude", magnitude, "magnitudeConfig", magnitudeConfig,
             "quake_intensity", quake_intensity, "centerIntensityConfig",
             centerIntensityConfig)
    if intensityLocal > intensityLocalLast then
        log.info("intensityLocal:", intensityLocal, "intensityLocalLast:",
                 intensityLocalLast)
        if not doToneTask then toneBreak = true end
        while not doToneTask do sys.wait(300) end
        if not DoLampTaskEarthquake then lampBreak = true end
        while not DoLampTaskEarthquake do sys.wait(300) end
        if not doSignalTask then signalBreak = true end
        while not doSignalTask do sys.wait(300) end
        if not doEmergencyLightOpen then emergencyLightOpenBreak = true end
        if not send433RFSignal.TimeId then
            send433RFSignal.InterruptSendMsg = false
            send433RFSignal.sendMsgTask()
        end
        intensityLocalLast = intensityLocal
        if intensityLocal >= intensity and magnitude >= magnitudeConfig and
            quake_intensity >= centerIntensityConfig then
            sysTime = GetSystemTime()
            eqlog = eqlog .. "[" .. sysTime .. "]" ..
                        "本地计算-达到设定阀值！\n"
            if countDownS > 0 then
                while not DoLampTaskEarthquake do sys.wait(300) end
                if intensity2Threshold(intensityLocal) >= countDown then
                    if "0101" == msgCode or "0102" == msgCode or not regCenter then -- 普通预警，专业预警,keson转发预警
                        sysTime = GetSystemTime()
                        eqlog = eqlog .. "[" .. sysTime .. "]" ..
                                    "本地计算-达到本地预警音阀值！\n"
                        sys.wait(300)
                        sys.taskInit(alarmVoiceTask, countDownS)
                    elseif "0201" == msgCode or "0202" == msgCode then -- 普通预警演习，专业预警演习
                        ttsStr = exerciseText .. exerciseText .. exerciseText
                        sys.wait(300)
                        sys.taskInit(alarmDrillVoiceTask, countDownS)
                    elseif "0301" == msgCode or "0302" == msgCode then -- 普通预警测试，专业预警测试
                        ttsStr = exerciseText .. exerciseText .. exerciseText
                        sys.wait(300)
                        sys.taskInit(alarmDrillVoiceTask, countDownS)
                    end
                else
                    sysTime = GetSystemTime()
                    eqlog = eqlog .. "[" .. sysTime .. "]" ..
                                "[不满足报警音临界值：]" ..
                                "烈度阈值：" ..
                                intensity2Threshold(intensityLocal) ..
                                ",报警音预设值：" .. tostring(alertSound) ..
                                "[执行报警音任务:]" ..
                                tostring(doToneTask) .. "\n"
                end
                -- 报警灯任务
                log.info("alertLight", alertLight, "intensityLocal",
                         intensityLocal)
                if intensityLocal >= alertLight and DoLampTaskEarthquake then
                    sysTime = GetSystemTime()
                    eqlog = eqlog .. "[" .. sysTime .. "]" ..
                                "本地计算-达到本地预警灯阀值！\n"
                    sys.wait(200)
                    sys.taskInit(alarmLampOperationTask, countDownS,
                                 intensityLocal)
                else
                    sysTime = GetSystemTime()
                    eqlog = eqlog .. "[" .. sysTime .. "]" ..
                                "[不满足报警灯临界值：]" ..
                                "烈度：" .. tostring(intensityLocal) ..
                                ",报警灯预设值：" .. tostring(alertLight) ..
                                "[执行报警灯任务:]" ..
                                tostring(DoLampTaskEarthquake) .. "\n"
                end
                while not doSignalTask do sys.wait(300) end
                -- 433信号发送任务
                if (intensity2Threshold(intensityLocal) >= alertSound or
                    intensity2Threshold(intensityLocal) >= emergencyLamp) and
                    enable433 then
                    eqlog = eqlog .. "[" .. sysTime .. "]" ..
                                "本地计算-达到本地发送433所需条件阀值！\n"
                    sys.wait(200)
                    sys.taskInit(send433SignalTask, countDownS, intensityLocal)
                    sys.taskInit(emergencyLightOpenTask)
                else
                    sysTime = GetSystemTime()
                    eqlog = eqlog .. "[" .. sysTime .. "]" ..
                                "[阈值，发送433，执行发送433信号存在条件不满足]" ..
                                "烈度转阈值：" ..
                                intensity2Threshold(intensityLocal) ..
                                ",设定阈值：" .. tostring(alertSound) ..
                                "是否发送433:" .. tostring(enable433) ..
                                "执行发送433信号任务" ..
                                tostring(doSignalTask) .. "\n"
                end
                while not doToneTask do sys.wait(800) end
                -- sys.taskInit(mqttQuakAlarmSendTask, intensity, countDownS)
            end
        else
            intensityLocalLast = 0
            sysTime = GetSystemTime()
            eqlog = eqlog .. "[" .. sysTime .. "]" ..
                        "[不满足预警临界值：]" .. "烈度：" ..
                        tostring(intensityLocal) .. ",烈度预设值：" ..
                        tostring(intensity) .. ",震级:" .. tostring(magnitude) ..
                        ",震级预设值:" .. tostring(magnitudeConfig) ..
                        ",震中烈度:" .. tostring(quake_intensity) ..
                        ",震中烈度预设值:" ..
                        tostring(centerIntensityConfig) .. "\n"
        end
    else
        sysTime = GetSystemTime()
        eqlog = eqlog .. "[" .. sysTime .. "]" ..
                    "[最新计算出的设备所在地震动烈度小于上次正在播报的震动烈度，不予播报！！]" ..
                    "最新震动烈度：" .. tostring(intensityLocal) ..
                    ",上次未播报结束烈度：" ..
                    tostring(intensityLocalLast) .. "\n"
    end

    -- 烈度回传事件  科信系统
    if intensityLocal >= intensityReturn then
        log.info("intensityReturn", intensityReturn)
        intensityReturnTask(intensityLocal, tjsondata, earthquakeTopic,
                            countDownS, quakeTimeStr, focal_longitude, distance,
                            placeName, focal_latitude)
        -- sys.taskInit(intensityReturnTask, intensity, tjsondata, earthquakeTopic, countDownS, quakeTimeStr,
        --     focal_longitude, distance, placeName, focal_latitude)
    else
        sysTime = GetSystemTime()
        eqlog = eqlog .. "[" .. sysTime .. "]" ..
                    "[不满足烈度回传临界值：]" .. "烈度：" ..
                    tostring(intensityLocal) .. ",烈度回传预设值：" ..
                    tostring(intensityReturn) .. "\n"
    end
    -- 其他系统预警消息返回
    if regCenter then
        eathquakeWarningReportRegCenter(intensityLocal, distance,
                                        tostring(countDownS))
    end
    actionMark = false
end

-- 地震预警主逻辑
function EarthquakeWarning(aesDecryptMsg, tjsondata, earthquakeTopic)
    receiveTime = GetSystemTime()
    errlog, eqlog = "", ""
    if "true" == regCenter then
        regCenter = true
    elseif "false" == regCenter then
        regCenter = false
    end
    if alertVolume <= 75 and alertVolume > 50 then
        setGpio1Fnc(1)
        log.info("音量为75")
    elseif alertVolume <= 50 and alertVolume > 20 then
        setGpio16Fnc(1)
        log.info("音量为50")
    elseif alertVolume <= 25 and alertVolume > 0 then
        setGpio17Fnc(1)
        log.info("音量为25")
    end
    sysTime = GetSystemTime()
    alert_parameter_assembly(tjsondata)
    log.info("Equipment_latitude", getLbsLoc.Lat, "Equipment_longitude",
             getLbsLoc.Lng)
    if longitude == "" and latitude == "" then
        longitude = getLbsLoc.Lng
        latitude = getLbsLoc.Lat
    end
    eqlog =
        eqlog .. "[" .. sysTime .. "]" .. "[设备位置信息:]" .. "Lng:" ..
            tostring(longitude) .. ",Lat:" .. tostring(latitude) .. "\n"
    if regCenter then -- 启用注册中心
        if "0199" == msgCode then
            log.info("eventCancelID:", eventCancelID, "eEWID:", eEWID,
                     "producerID:", producerID, "producerCancelID:",
                     producerCancelID)
            log.info("eventCancelID == eEWID:", eventCancelID == eEWID,
                     "producerID == producerCancelID:",
                     producerID == producerCancelID)
            if eventCancelID == eEWID then
                log.info("TESTCANCEL")
                sys.taskInit(cancel_alert_event) -- 取消地震预警
            end
        else
            sys.taskInit(earthquake_alert_action, aesDecryptMsg, tjsondata,
                         earthquakeTopic) -- 地震预警动作执行
            log.info("地震预警动作执行结束")
        end
    else -- keson转发地震预警信息
        if "0199" == msgCode or quake_intensity == 0 then
            sys.taskInit(cancel_alert_event)
        else
            while actionMark do sys.wait(800) end
            sys.taskInit(earthquake_alert_action, aesDecryptMsg, tjsondata,
                         earthquakeTopic)
        end
    end
    if eqlog ~= nil and eqlog ~= false then
        logGenerator.generateLogTask(eqlog, "log")
    end
    if errlog ~= "" and errlog ~= false then
        logGenerator.generateLogTask(errlog, "log")
    end
end
